package com.m3839.sdk.login.core;

import android.app.Activity;
import android.text.TextUtils;

import com.m3839.sdk.anti.core.AntiManager;
import com.m3839.sdk.common.core.ApiError;
import com.m3839.sdk.common.core.Constant;
import com.m3839.sdk.common.core.ErrorConstant;
import com.m3839.sdk.common.core.SdkConfiguration;
import com.m3839.sdk.common.event.SubjectBus;
import com.m3839.sdk.common.util.ConditionUtils;
import com.m3839.sdk.common.util.LogUtils;
import com.m3839.sdk.login.HykbUser;
import com.m3839.sdk.login.bean.GameConfig;
import com.m3839.sdk.login.bean.InternalTip;
import com.m3839.sdk.login.bean.InternalUser;
import com.m3839.sdk.login.listener.HykbLoginListener;
import com.m3839.sdk.login.model.LoginApiModel;
import com.m3839.sdk.login.model.api.ILoginModel;
import com.m3839.sdk.login.ui.controller.ILoginUiController;
import com.m3839.sdk.login.ui.controller.LoginUiControllerImpl;
import com.m3839.sdk.login.utils.UserUtils;

import java.util.Observable;
import java.util.Observer;

/**
 * @author ChenBaoyang
 * @description: LoginManager
 * @date 2021/11/15 14:52
 */
public class LoginManager {

    private static final long DAY_UNIT = 24 * 60 * 60;

    private Activity activity;

    private HykbLoginListener listener;

    /** 内部使用的用户数据对象 */
    private InternalUser internalUser;

    /** 登录访问服务端的接口 */
    private final ILoginModel loginModel;

    /** 对外用户信息数据对象 */
    private HykbUser user;

    /** 上一次登录的用户uid */
    private String lastUserId;

    /** 登录相关涉及登录UI的统一控制接口 */
    private final ILoginUiController loginUiController;

    private LoginManager() {
        loginModel = new LoginApiModel();
        loginUiController = new LoginUiControllerImpl();

        // 监听防沉迷抛过来的切换账号事件
        SubjectBus.get().observe(Constant.HYKB_EVENT_ANTI_SWITCH_ACCOUNT, new Observer() {
            @Override
            public void update(Observable o, Object arg) {
                switchUSerInternal();
            }
        });

        // 监听防沉迷抛过来的注销账号事件
        SubjectBus.get().observe(Constant.HYKB_EVENT_ANTI_RESET, new Observer() {
            @Override
            public void update(Observable o, Object arg) {
                logout();
            }
        });

        // 监听防沉迷抛过来的回调事件
        SubjectBus.get().observe(Constant.HYKB_EVENT_ANTI_CALLBACK, new Observer() {
            @Override
            public void update(Observable o, Object arg) {
                ApiError apiError = (ApiError) arg;
                handleErrorCallback(apiError.code, apiError.message);
            }
        });
    }

    /**
     * 返回HykbLoginManager对象
     */
    public static LoginManager getInstance() {
        return SingletonHolder.INSTANCE;
    }

    private static class SingletonHolder {
        private static final LoginManager INSTANCE = new LoginManager();
    }

    /**
     * 对外调用的登录入口
     *
     * @param activity   Activity  上下文
     * @param switchUser Boolean  用来表示是否是切换账号操作
     * @param listener   LoginListener  登录回调监听
     */
    public void doLogin(Activity activity, boolean switchUser, HykbLoginListener listener) {

        this.activity = activity;
        this.listener = listener;

        if(!ConditionUtils.commonCondition(activity, new ConditionUtils.ConditionCallback() {
            @Override
            public void callback(int code, String message) {
                // 通用条件的回调
                handleErrorCallback(code, message);
            }
        })){
            return;
        }

        if (!InitManager.getInstance().isInitOk()) {
            //未初始化成功，不让调用登录
            handleErrorCallback(ErrorConstant.HYKB_CODE_SDK_NOT_INIT_OK,
                    ErrorConstant.ERR_MSG_SDK_NOT_INIT_OK);
            return;
        }

        if (switchUser) {
            //表示切换账号
            loginUiController.callLoginHostPage(activity);
            return;
        }

        if (user != null) {
            //当前已经登录了，直接返回用户信息
            handleSuccessCallback();
            return;
        }

        boolean fromPaid = UserStorage.getFlag(activity);
        LogUtils.flog("fromPaid = " + fromPaid);
        //判断是否直接用付费下载的用户信息
        if (fromPaid && readUserCache()) {
            return;
        }

        //检查用户缓存是否在有效期内
        if (checkUserCache()) {
            return;
        }

        //触发内部登录（授权或者web登录）
        loginUiController.callLoginHostPage(activity);
    }


    /**
     * 检查用户缓存数据
     *
     * @return Boolean
     */
    private boolean checkUserCache() {
        //根据服务端给的有效期确认是否走缓存数据
        GameConfig config = InitManager.getInstance().getInitConfig();
        if (config.getValidity() > 0) {
            // 获取本地缓存
            long firstTime = UserStorage.getFirstTime(activity) * 1000L;
            // 判断下是否有缓存，如果没有照样走手动登录
            long expireTime = firstTime + DAY_UNIT * config.getValidity() * 1000L;
            //判断有缓存数据，切在有效期内
            long currentTime = System.currentTimeMillis();
            if (firstTime > 0 && firstTime < currentTime && currentTime < expireTime) {
                return readUserCache();
            }
        }
        return false;
    }

    /**
     * 读取用户缓存信息
     *
     * @return true:成功，false：失败
     */
    private boolean readUserCache() {
        String nick = UserStorage.getUserNick(activity);
        String state = UserStorage.getUserState(activity);
        String[] info = state.split("\\|");

        if (info.length > 2) {
            // 创建用户信息实体对象，用户信息验证
            createUser(info[0], nick, info[1], info[2]);
            return true;
        }

        return false;
    }

    /**
     * 创建用户信息对象
     *
     * @param uid   快爆用户ID
     * @param nick  快爆用户昵称
     * @param type  快爆用户登录方式
     * @param token 快爆用户token
     */
    public void createUser(String uid, String nick, String type, String token) {
        internalUser = new InternalUser(uid, nick, type, token);
        LogUtils.flog(internalUser.toString());

        // 监听用户登录成功
        observeLoginSuccess();

        // 监听用户登录失败
        observeLoginFailed();

        // 监听用户封禁或者强登
        observeLoginBanned();

        // 用户信息校验
        loginModel.authCheck(internalUser);
    }

    /**
     * 监听用户登录成功
     */
    private void observeLoginSuccess() {
        SubjectBus.get().observe(Constant.HYKB_EVENT_LOGIN_SUCCESS, new Observer() {
            @Override
            public void update(Observable o, Object arg) {
                if (arg != null) {
                    internalUser.setAccessToken((String) arg);
                }
                //创建外部用户数据实体对象
                user = new HykbUser(internalUser.getUserId(), internalUser.getNick(), internalUser.getAccessToken());

                //关闭所有相关弹窗
                loginUiController.dismissAllLoginDialog();

                // 缓存用户信息
                cacheUserInfo();

                // 校验成功之后回调给游戏方
                handleSuccessCallback();

                // 处理防沉迷
                handleAnti();

            }
        });
    }

    /**
     * 缓存用户信息
     */
    private void cacheUserInfo() {
        UserStorage.clearCache(activity.getApplicationContext());
        UserStorage.saveUserNick(activity.getApplicationContext(), internalUser.getNick());
        UserStorage.saveUserState(activity.getApplicationContext(), UserUtils.getState(internalUser));
        UserStorage.saveFirstTime(activity.getApplicationContext(),
                System.currentTimeMillis() / 1000);
    }

    /**
     * 处理防沉迷内容
     */
    private void handleAnti() {

        // 先清除掉防沉迷的token，以防切换账号，切换回来是相同的账号
        AntiManager.getInstance().resetToken();

        // 账号变化了，先做防沉迷关闭操作
        if (!TextUtils.isEmpty(lastUserId) && !TextUtils.equals(lastUserId, internalUser.getUserId())) {
            AntiManager.getInstance().stopFcm();
        }

        //开启防沉迷检测
        AntiManager.getInstance().checkFcm(activity, internalUser.getUserId(),
                internalUser.getNick(), internalUser.getType(), internalUser.getToken());

        //缓存最新的账号的uid
        lastUserId = internalUser.getUserId();
    }

    /**
     * 监听用户封禁或者强登
     */
    private void observeLoginFailed() {
        SubjectBus.get().observe(Constant.HYKB_EVENT_LOGIN_FAILED, new Observer() {
            @Override
            public void update(Observable o, Object arg) {
                // 用户校验失败
                logout();
                ApiError error = (ApiError) arg;
                handleErrorCallback(error.code, error.message);
                LogUtils.flog(error.message);
            }
        });
    }

    /**
     * 监听用户登录失败
     */
    private void observeLoginBanned() {
        SubjectBus.get().observe(Constant.HYKB_EVENT_LOGIN_BANNED, new Observer() {
            @Override
            public void update(Observable o, Object arg) {
                logout();
                loginUiController.showLoginTipDialog(activity, (InternalTip) arg);
            }
        });

    }

    /**
     * 注销登录
     */
    public void logout() {
        //注销账号，清除用户信息, 结束防沉迷
        if (user != null) {
            AntiManager.getInstance().stopFcm();
            user = null;
            internalUser = null;
        }
        UserStorage.clearCache(SdkConfiguration.getAppContext());
    }

    /**
     * 用户信息来子防沉迷的
     */
    public void createUserFrom(Activity activity) {
        String nick = UserStorage.getUserNick(activity.getApplicationContext());
        String state = UserStorage.getUserState(activity.getApplicationContext());
        String[] infos = state.split("\\|");
        if (infos.length > 0) {
            user = new HykbUser(infos[0], nick, null);
        }
    }


    /**
     * 切换账号
     */
    public void switchUSerInternal() {
        loginUiController.callLoginHostPage(activity);
    }

    /**
     * 登录失败的回调
     *
     * @param code
     * @param message
     */
    public void handleErrorCallback(int code, String message) {
        if (listener != null) {
            listener.onLoginFailed(code, message);
        }
    }

    /**
     * 登录成功的回调
     */
    public void handleSuccessCallback() {
        if (listener != null) {
            listener.onLoginSuccess(user);
        }
    }

    /**
     * 内部使用的用户数据实体类
     * @return
     */
    public InternalUser getInternalUser() {
        return internalUser;
    }

    /**
     * 对外的用户数据实体类
     * @return
     */
    public HykbUser getUser() {
        return user;
    }

    /**
     * 判断是否登录成功
     * @return
     */
    public boolean isLogin() {
        return user != null;
    }
}
